Skip to content

test: address PR #18 review — Phase 1.C / per-stem / dsp_utils coverage + comment + schema fixes - #19

Merged
slittycode merged 1 commit into
feat/phase-1-depth-audit-and-gate-v3from
claude/split-types-modules-Rs9wv
May 12, 2026
Merged

test: address PR #18 review — Phase 1.C / per-stem / dsp_utils coverage + comment + schema fixes#19
slittycode merged 1 commit into
feat/phase-1-depth-audit-and-gate-v3from
claude/split-types-modules-Rs9wv

Conversation

@slittycode

Copy link
Copy Markdown
Owner

Addresses the blocking + should-fix + nit findings from the self-review on #18
(which GitHub rejected because you can't request changes on your own PR).
Stacks onto feat/phase-1-depth-audit-and-gate-v3 so the fixes flow into #18
when this lands.

Findings addressed

Blocking — missing unit-test coverage on PR #18

  1. Phase 1.C analyzers — new BandDrumDetailTests, SnareDetailTests,
    HihatDetailTests, TransientDensityDetailTests, SaturationDetailTests
    in apps/backend/tests/test_analyze.py. Each covers null/short/silent
    input guards, schema-field presence, and at least one behavioral
    assertion against a synthetic signal that should trip the detector
    (band-limited hits, mid-band onset density, hard-clipped vs dynamic
    signal, etc.). Same pattern as the existing ReverbDetailTests /
    BassDetailTests classes.
  2. _run_per_stem_analyses — new RunPerStemAnalysesTests covers
    stems=None, empty dict, all loads failing, two-stem success with
    schema shape check, "one analyzer raises for one stem, others
    succeed", and the stereo-load-skipped path (LUFS/stereoDetail/truePeak
    omitted but mono fields still present).
  3. dsp_utils.py — new apps/backend/tests/test_dsp_utils.py with
    direct tests for _pearson_corr (perfect ±1, orthogonal ≈ 0, constant
    → NaN, empty → NaN, unequal-length truncation), _downsample_lufs_array,
    _downsample_band_energies_curve, _compute_tempo_curve_from_ticks
    (steady 120 BPM resolves to 120, tempo change is reflected in curve range,
    zero/negative intervals don't produce inf), and
    _compute_stereo_correlation_curve (identical L/R → +1, inverted → -1,
    silent sub band → None).
  4. averageDecayMs > 0 regression — new
    test_average_decay_ms_is_positive_for_bass_pulses in BassDetailTests.
    Synthesizes eight 60 Hz pulses with a ~123 ms expected decay-to-half
    and asserts averageDecayMs ≥ 30 ms — comfortably above the pre-fix
    sub-ms range, while still being a positive bound that catches regression.

Should fix

  1. pathCoversTracked docstring — rewrote the comment in
    apps/ui/src/services/phase2Validator.ts to match what the code
    actually does. The old text said stemAnalysis.* won't match
    stemAnalysis.drums.spectralBalance, but the implementation's
    ts.length <= cs.length branch runs as a wildcard-prefix scan, so it
    does match. New text walks through both examples explicitly.

Worth considering (nit)

  1. bassDetail.fundamentalHz schema note — added an approximation
    warning to apps/backend/JSON_SCHEMA.md: ZCR/2 equals f₀ only for
    pure sinusoids; harmonic-rich basses bias upward; prefer pitchDetail
    when stems are available; avoid driving a narrow filter Q within
    ±15 Hz without corroborating evidence.

Test results

  • python3.11 -m unittest tests.test_dsp_utils28/28 OK (0.034 s)
  • python3.11 -m unittest tests.test_analyze.{BandDrumDetailTests,SnareDetailTests,HihatDetailTests,TransientDensityDetailTests,SaturationDetailTests,RunPerStemAnalysesTests,BassDetailTests}37/37 OK (4.168 s combined with dsp_utils above for 65/65 OK across all new + modified)
  • npm run lint → clean (tsc --noEmit exit 0)
  • npm run test:unit275/275 OK (vitest unit suite)

Environmental errors in the broader backend suite (matplotlib / torch /
db modules) are unrelated to this change and were present pre-commit on
the same branch tip.

Test plan

  • Backend: new analyzer + orchestrator + dsp_utils tests pass locally
  • Backend: BassDetailTests regression test for averageDecayMs passes
  • Frontend: phase2Validator.test.ts (50 tests) still passes — comment
    change does not alter behavior
  • Frontend: tsc --noEmit clean
  • Reviewer to spot-check the schema note wording in JSON_SCHEMA.md

Generated by Claude Code

…rator, and dsp_utils

Closes the test-coverage gaps flagged in the PR review.

Backend:
- test_analyze.py: new BandDrumDetailTests, SnareDetailTests, HihatDetailTests,
  TransientDensityDetailTests, SaturationDetailTests, RunPerStemAnalysesTests.
  Each covers null/short/silent input guards, schema-field presence, and at
  least one behavioral assertion against a synthetic signal that should trip
  the detector. RunPerStemAnalysesTests covers stems=None, empty dict, all
  loads failing, mono+stereo success, partial-analyzer failure, and the
  stereo-load-skipped path.
- BassDetailTests: regression test for averageDecayMs > 30 ms on a synthetic
  decaying-pulse signal — guards the envelope-based fix from sliding back to
  the pre-fix sub-millisecond range.
- test_dsp_utils.py (new): direct tests for _pearson_corr,
  _downsample_lufs_array, _downsample_band_energies_curve,
  _compute_tempo_curve_from_ticks, and _compute_stereo_correlation_curve,
  with closed-form expected values for perfect/anti/orthogonal correlation,
  constant-input NaN handling, tempo-change detection, and the silent-sub
  None policy.

Docs / comments:
- JSON_SCHEMA.md: flag bassDetail.fundamentalHz as a ZCR approximation that
  biases upward on harmonic-rich basses; steer Phase 2 to prefer
  pitchDetail when stems are available and avoid narrow filter-Q moves
  within ±15 Hz of the value.
- phase2Validator.ts: rewrite the pathCoversTracked docstring so it
  matches what the code actually does (a wildcard token covers all longer
  citation paths under the same prefix; "stemAnalysis.*" does match
  "stemAnalysis.drums.spectralBalance").
@slittycode
slittycode marked this pull request as ready for review May 12, 2026 07:26
@slittycode
slittycode merged commit 334d379 into feat/phase-1-depth-audit-and-gate-v3 May 12, 2026
@slittycode
slittycode deleted the claude/split-types-modules-Rs9wv branch May 12, 2026 07:26
slittycode added a commit that referenced this pull request May 13, 2026
…g completion (#18)

* feat: Phase 1.A–1.D depth additions, Track 2 audit, decision-gate v3 + catalog completion

Substantial measurement-depth pass on the ASA Phase 1 pipeline plus a
trustworthy multi-model decision-gate harness. Default Gemini model
(gemini-2.5-flash) now PASSes the stem-aware gate on the Vtss bench
track; Live 12 catalog completion drops UNKNOWN_PARAMETER 16 → 1
across all v3.1 snapshots.

## Depth additions (Phase 1.A – 1.D)

- Phase 1.A cheap wins (5): per-frame short-term LUFS curve, per-frame
  7-band spectral balance time series, instantaneous tempoCurve,
  per-second stereo correlationCurve, 256-point arrangement
  noveltyCurve (up from 64).
- Phase 1.B stem-first refactor: per-stem subtree under
  ``stemAnalysis.{drums,bass,other,vocals}`` with the same shape as
  the full-mix analyzers. Phase 2 can now cite element-specific
  measurements.
- Phase 1.C #0 real time-signature detection (onset-accent
  autocorrelation, replaces the always-4/4 fallback).
- Phase 1.C #1 per-band transient density across the 7
  spectralBalance bands (kick / hi-hat density anchors).
- Phase 1.C #2 per-band stereo correlations (Utility-width-per-band
  recommendations).
- Phase 1.C #3 ``grooveDetail.perDrumSwing.{kick,snare,hihat}`` from
  the mid-band beat-loudness signal.
- Phase 1.C #4 snareDetail / hihatDetail band-limited drum character
  (hits, attack sharpness, body/snap energy ratio, decay).
- Phase 1.C #5 saturationDetail (clipped sample count, peakRatio95to50,
  rmsToPeakRatioDb, saturationLikely).
- Phase 1.C #6 32nd-note sidechain resolution + envelopeShape32
  (legacy envelopeShape preserved via max-pairing downsample);
  pumpingRate now four-valued including thirty_second.
- Phase 1.D #5 RT60 reverb per stem with perBandRt60 (low / lowMids /
  highMids / highs) + preDelayMs via Schroeder-equivalent slope fit.
  Wired through stemAnalysis.{stem}.reverbDetail.

## Track 2 audit pass 1 + measurement-quality fixes

- New ``scripts/audit_pass1.py`` harness — structured 12-section
  markdown audit comparing real-track Phase 1 measurements against
  declared ground truth and sanity rules.
- Bug fix: ``bassDetail.averageDecayMs`` was 0 ms on real bass
  material (Codex PDF finding reproduced). Root cause: decay loop
  searched from onset rather than peak, and checked the raw
  oscillating waveform rather than an envelope. Fixed with a 20 ms
  RMS envelope + peak-anchored search. Synthetic validation: 350 ms
  theoretical → 346 ms measured; 35 ms → 37 ms. Real-track Vtss:
  0 ms (FAIL) → 66–125 ms (PASS).
- Bug fix: ``vocalDetail.hasVocals = true`` false positive on
  instrumental synth content. Added temporal-formant-stability check
  (sustained synth leads have near-static "formants"; real vocals
  shift formants 100+ Hz with syllables); tightened formant tolerance
  200 → 100 Hz; raised threshold 0.45 → 0.55. No-stem run on Vtss now
  correctly reports hasVocals=false at conf 0.48.
- Pre-existing import bugs in ``analyze_segments.py``:
  ``_compute_stereo_metrics`` (from dsp_utils) and ``Counter`` (from
  collections) were undefined. ``segmentStereo`` + ``chordDetail``
  now populate correctly.

## Phase 2 contract + validator + decision gate

- Phase 2 prompt v3: per-stem path enumeration, citation contract
  (``phase1Fields`` required on every recommendation), "Phase-2
  self-reference is not a citation" rule, dedicated sections for
  snare/hi-hat character, saturation, sidechain envelope, reverb
  detail.
- Phase 2 schema (``server_phase2.py``): ``phase1Fields`` array
  required on ``mixAndMasterChain``, ``abletonRecommendations``, and
  ``secretSauce.workflowSteps`` items.
- Frontend validator (``phase2Validator.ts``) overhaul:
    * 8 violation types (NUMERIC_OVERRIDE, GENRE_IGNORES_DSP,
      BOUNDS_VIOLATION, MISSING_CITATION, TRIVIAL_CITATIONS,
      NEW_FIELD_UNCITED, LOW_CONFIDENCE_NOT_HEDGED, RECOMMENDATION_SALVAGED).
    * Bidirectional + wildcard ``pathCoversTracked`` matcher so leaf
      citations satisfy parent tracked paths and ``stemAnalysis.*``
      wildcards work.
    * 19 tracked Phase 1.A + Phase 1.C/D field paths (was 7).
- Decision-gate vitests (4): single-, multi-, real-, and stem-aware
  multi-model comparators that read ``/tmp/decision_gate_*.json``
  snapshots and emit per-model markdown reports.

## Live 12 catalog completion (UNKNOWN_PARAMETER closure)

- Auto Filter: ``parameterAliases`` flat-map
  ``{"Filter Resonance": "Resonance", "Filter Frequency": "Frequency"}``.
  Closes the instrument-side long-form naming bleed.
- Glue Compressor: ``allowedParameters`` expanded by 4
  (Range, Sidechain, Sidechain Gain, Sidechain Dry/Wet).
- ``_validate_phase2_catalog_entry`` resolves aliases before the
  membership check; startup-time loader validates the new
  ``parameterAliases`` shape.
- New ``Phase2CatalogValidationTests`` (11 cases) covers alias
  resolution, expansion, scoping per-device, and negative cases.
- New ``scripts/replay_catalog_validation.py`` — no-Gemini-spend
  harness that re-validates v3.1 snapshots against the live catalog.
  Verdict: UNKNOWN_PARAMETER drops 16 → 1 across all 8 snapshots;
  the remaining hit is ``EQ Eight / "Band 8 Filter Type"`` (separate
  device, v3.2-target).

## Test state

- Backend: 374 tests pass (was 363; +11 ``Phase2CatalogValidationTests``).
- Frontend: 296 tests pass (was 286; +10 validator bidirectional /
  wildcard tests).
- UI lint clean (``tsc --noEmit``).

## Out of scope / follow-ups (documented in SESSION_BLITZ + plan)

- Pro-model citation-depth iteration (3-pro and 3.1-pro still cite
  far less Phase 1.C/D than 2.5-flash).
- gemini-3.1-pro-preview ``DROPPED_INVALID_ARRAY_ITEM`` salvage
  regression seen in earlier v3 runs.
- Compressor "Sustain", "Ableton Project Settings", "Mixer" device
  hits — v3.2 prompt-fix targets.
- Phase 1.D #1 madmom integration (prototype proven, install path
  documented at ``.runtime/reports/madmom_install_prototype_2026-05-12.md``).
- Phase 1.D #2 chord progression deeper labelling.
- ``JSON_SCHEMA.md`` documentation of the catalog schema
  (``parameterAliases`` field).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(backend): add coverage for Phase 1.C analyzers, per-stem orchestrator, and dsp_utils (#19)

Closes the test-coverage gaps flagged in the PR review.

Backend:
- test_analyze.py: new BandDrumDetailTests, SnareDetailTests, HihatDetailTests,
  TransientDensityDetailTests, SaturationDetailTests, RunPerStemAnalysesTests.
  Each covers null/short/silent input guards, schema-field presence, and at
  least one behavioral assertion against a synthetic signal that should trip
  the detector. RunPerStemAnalysesTests covers stems=None, empty dict, all
  loads failing, mono+stereo success, partial-analyzer failure, and the
  stereo-load-skipped path.
- BassDetailTests: regression test for averageDecayMs > 30 ms on a synthetic
  decaying-pulse signal — guards the envelope-based fix from sliding back to
  the pre-fix sub-millisecond range.
- test_dsp_utils.py (new): direct tests for _pearson_corr,
  _downsample_lufs_array, _downsample_band_energies_curve,
  _compute_tempo_curve_from_ticks, and _compute_stereo_correlation_curve,
  with closed-form expected values for perfect/anti/orthogonal correlation,
  constant-input NaN handling, tempo-change detection, and the silent-sub
  None policy.

Docs / comments:
- JSON_SCHEMA.md: flag bassDetail.fundamentalHz as a ZCR approximation that
  biases upward on harmonic-rich basses; steer Phase 2 to prefer
  pitchDetail when stems are available and avoid narrow filter-Q moves
  within ±15 Hz of the value.
- phase2Validator.ts: rewrite the pathCoversTracked docstring so it
  matches what the code actually does (a wildcard token covers all longer
  citation paths under the same prefix; "stemAnalysis.*" does match
  "stemAnalysis.drums.spectralBalance").

Co-authored-by: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
slittycode added a commit that referenced this pull request May 31, 2026
…record (#124)

* docs: refresh stale items vs current code; archive completed hosting record

Sweep against the 2026-05-30 audit findings — the doc surface had drifted
through the MT3, Live 12 catalogue, pianoroll/symusic, and recommendation-proof
merges. Adds those features to the inventories where they were missing, fixes
a wrong line reference, removes a dead commit hash, refreshes date stamps, and
archives a completed-work record.

- MT3 polyphonic transcription: add to apps/backend/AGENTS.md (file map +
  guidance), apps/backend/ARCHITECTURE.md (Components table + mt3-transcriptions
  route), apps/backend/README.md (Polyphonic section now reflects opt-in shipping),
  apps/ui/AGENTS.md + apps/ui/README.md (mt3Client.ts + UI surface), CLAUDE.md
  (#19 backend file, #6a frontend service), and all three CHANGELOG.md files.
- Live 12 catalogue + phase2_catalogue_gates, transcription pianoroll +
  symusic, recommendation-proof campaign: add to CHANGELOG.md (root) and
  apps/backend/CHANGELOG.md and apps/ui/CHANGELOG.md.
- CLAUDE.md: fix wrong analysis_runtime.py line ref (685 → ~800), add
  ASA_ENABLE_MT3 and ASA_SAMPLE_SYNTH_BACKEND env vars, correct the tsconfig
  excludes description, drop the unreachable 5c40dd4 commit hash.
- apps/backend/AGENTS.md + ARCHITECTURE.md: drop the same dead 5c40dd4 hash.
- docs/ARCHITECTURE_STRATEGY.md + docs/POLYPHONIC_TRANSCRIPTION_SPIKE.md:
  reflect that MT3 has shipped as an opt-in, additive stage (the spike harness
  remains the offline comparison rig for other candidates).
- docs/SAMPLE_GENERATION.md: fix the schematic node label (synth_kit() → the
  real synth_kick/snare/hat() trio).
- apps/backend/JSON_SCHEMA.md: annotate the shared-vs-full carve-out so the
  full-mode-only keys (keyProfile, tuningFrequency, tuningCents,
  lufsMomentaryMax, lufsShortTermMax, pitchDetail) are explicit per CLAUDE.md
  tripwire #4.
- Archive docs/PUBLIC_HOSTING_FOUNDATION.md → docs/history/public-hosting-foundation-2026-04-01.md
  with an archived-banner; update inbound references in CHANGELOG.md, docs/SETUP.md,
  docs/history/README.md, and docs/history/archive/refactor-state-2026-03-18.md.
- incorporations/forking-plans-2026-05-14.md: add a 2026-05-30 status update
  noting Plan 6 substantially landed via the Live 12 catalogue + gates work.

No code touched — markdown only.

https://claude.ai/code/session_016m6cUFNwb3kD2EzAbgqCHe

* docs: fix self-contradictory archive banner phrasing

The banner said the "Remaining work" section "lives outside this archived
doc" but that section is in the doc itself. Aligns with the clearer phrasing
already used in docs/history/README.md.

https://claude.ai/code/session_016m6cUFNwb3kD2EzAbgqCHe

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants